#light

namespace Langexplr.Abc

open System.IO

module TypeEncodingUtilities =        
    
   let ReadS24Value(input : BinaryReader) : int =
    let number =  (int( input.ReadByte() ) |||
                   (int( input.ReadByte() ) <<< 8) ||| 
                     (int( input.ReadByte() ) <<< 16))
    in       
       if ((number &&& 0x200000) <> 0) then
          (number - 0xFFFFFF - 1) 
       else
          number
       
   let WriteS24Value(value : int,output : BinaryWriter) : unit =
      output.Write( (byte(uint32(0x000000FF) &&& uint32(value) ) ))
      output.Write( (byte(uint32(0x0000FF00) &&& uint32(value) >>> 8)))
      output.Write( (byte(uint32(0x00FF0000) &&& uint32(value) >>> 16)))
   
   
       
   let ReadU30Value(input : BinaryReader) : uint32 = 
      let firstByte = input.ReadByte()
        in 
          if ((firstByte &&& byte(0x80)) = byte(0)) then
             uint32(firstByte)
          else
            let secondByte = input.ReadByte()                       
               in
                 if (secondByte &&& byte(0x80) = byte(0)) then
                   (uint32(secondByte) <<< 7) ||| (uint32(firstByte) ^^^ uint32(0x80))
                 else
                    let thirdByte = input.ReadByte()  
                       in
                         if (thirdByte &&& byte(0x80) = byte(0)) then
                            (uint32(thirdByte) <<< 14) ||| 
                            ((uint32(secondByte) ^^^ uint32(0x80)) <<< 7) |||
                            (uint32(firstByte) ^^^ uint32(0x80)) 
                         else
                            let fourthByte = input.ReadByte()  
                               in
                                  if (fourthByte &&& byte(0x80) = byte(0)) then
                                     (uint32(fourthByte) <<< 21) ||| 
                                     ((uint32(thirdByte) ^^^ uint32(0x80)) <<< 14) ||| 
                                     ((uint32(secondByte) ^^^ uint32(0x80)) <<< 7) |||
                                     (uint32(firstByte) ^^^ uint32(0x80)) 
                                  else
                                     (uint32(input.ReadByte()) <<< 28) |||
                                     ((uint32(fourthByte) <<< 21) ^^^ uint32(0x80)) ||| 
                                     ((uint32(thirdByte) ^^^ uint32(0x80)) <<< 14) ||| 
                                     ((uint32(secondByte) ^^^ uint32(0x80)) <<< 7) |||
                                     (uint32(firstByte) ^^^ uint32(0x80)) 
   
   let CalculateU30Size(value : uint32) : int =                                   
         match value with
           | _ when (value < uint32(0x80)) -> 1
           | _ when (value < uint32(0x8000)) -> 2
           | _ when (value < uint32(0x800000)) -> 3
           | _ when (value < uint32(0x80000000)) -> 4
           | _ -> 5
           
   let WriteU30Value(value : uint32,output : BinaryWriter) : unit = 
      if (value < uint32(0x80)) then
        output.Write(byte(value))
      else
         if (value < uint32(0x8000)) then
           output.Write(byte(value &&& uint32(0X7F)) ||| byte(0x80))
           output.Write(byte(value >>> 7))
         else
            if (value < uint32(0x80000)) then
              output.Write(byte(value &&& uint32(0X7F)) ||| byte(0x80))
              output.Write(byte((value >>> 7) &&& uint32(0X7F)) ||| byte(0x80))
              output.Write(byte(value >>> 14))
            else
               if (value < uint32(0x80000000)) then
                  output.Write(byte(value &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte((value >>> 7) &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte((value >>> 14) &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte(value >>> 21))
               else
                  output.Write(byte(value &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte((value >>> 7) &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte((value >>> 14) &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte((value >>> 21) &&& uint32(0X7F)) ||| byte(0x80))
                  output.Write(byte(value >>> 28))
                                     
   let ReadStringInfo(input : BinaryReader) : string =
        let charCount = int(ReadU30Value(input));
          in new string(input.ReadChars(charCount))
          
   let WriteStringInfo(aStr : string,output : BinaryWriter) : unit =
        WriteU30Value(uint32(aStr.Length),output)
        output.Write(aStr.ToCharArray())
